import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.Random;

public class MatrixRain extends JPanel implements ActionListener, MouseMotionListener {
    // 屏幕尺寸
    private static final int WIDTH = 1200;
    private static final int HEIGHT = 800;

    // 字符大小
    private static final int FONT_SIZE = 14;

    // 列数和每行字符数
    private int columns;
    private int rows;

    // 存储每列的状态
    private Column[] columnsArray;

    // 随机数生成器
    private Random random;

    // 动画定时器
    private Timer timer;

    // 鼠标位置，用于交互效果
    private int mouseX = -100;
    private int mouseY = -100;

    // 字符集 - 更丰富的字符集合，更贴近电影
    private final String chars = "01アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヰヱヲンガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ" +
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
            "♠♥♦♣♂♀♪♫☼☽☾♦♧♨♩♬♭♮★☆♯†‡¶§‖¦©®™€$£¥¢¤";

    // 列类，存储每列的状态
    private class Column {
        int yPosition;          // 列的当前位置
        int speed;              // 下落速度
        int length;             // 字符流长度
        boolean active;         // 是否活跃
        int pauseCounter;       // 暂停计数器
        int pauseDuration;      // 暂停持续时间

        Column() {
            reset();
        }

        void reset() {
            // 随机起始位置，可能在屏幕上方
            yPosition = random.nextInt(-HEIGHT, 0);
            // 随机速度，增加变化性
            speed = random.nextInt(2, 6);
            // 随机长度，使字符流有长有短
            length = random.nextInt(5, 30);
            active = true;
            pauseCounter = 0;
            // 随机暂停时间，使某些列会暂停
            pauseDuration = random.nextInt(0, 50);
        }

        void update() {
            if (!active) {
                pauseCounter++;
                if (pauseCounter > pauseDuration) {
                    reset();
                }
                return;
            }

            yPosition += speed;

            // 当字符流完全离开屏幕时重置
            if (yPosition > HEIGHT + length * FONT_SIZE) {
                active = false;
            }
        }
    }

    public MatrixRain() {
        // 设置面板属性
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.BLACK);
        setDoubleBuffered(true); // 启用双缓冲，减少闪烁

        // 计算列数和行数
        columns = WIDTH / FONT_SIZE;
        rows = HEIGHT / FONT_SIZE;

        // 初始化列数组
        columnsArray = new Column[columns];
        for (int i = 0; i < columns; i++) {
            columnsArray[i] = new Column();
        }

        random = new Random();

        // 添加鼠标移动监听
        addMouseMotionListener(this);

        // 设置定时器，控制动画速度（更快的刷新频率）
        timer = new Timer(25, this);
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        // 启用抗锯齿，使字符更平滑
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        // 设置字体，更贴近电影中的等宽字体
        g2d.setFont(new Font("SimHei", Font.PLAIN, FONT_SIZE));

        // 绘制半透明黑色覆盖层，创建渐隐效果
        g2d.setColor(new Color(0, 0, 0, 20));
        g2d.fillRect(0, 0, WIDTH, HEIGHT);

        // 为鼠标位置创建扰动效果
        createMouseDisturbance();

        // 绘制每列的字符
        for (int i = 0; i < columns; i++) {
            Column col = columnsArray[i];
            if (!col.active && col.pauseCounter < col.pauseDuration / 2) {
                continue;
            }

            // 绘制字符流中的每个字符
            for (int j = 0; j < col.length; j++) {
                int y = col.yPosition - j * FONT_SIZE;

                // 只绘制在屏幕范围内的字符
                if (y > 0 && y < HEIGHT) {
                    // 计算亮度 - 字符流头部更亮，尾部渐暗
                    int alpha = 50 + (int)(150 * (1 - (float)j / col.length));
                    // 随机微调绿色值，增加变化
                    int green = 180 + random.nextInt(75);
                    g2d.setColor(new Color(0, green, 50, alpha));

                    // 随机选择字符
                    int charIndex = random.nextInt(chars.length());
                    char c = chars.charAt(charIndex);

                    // 偶尔随机替换字符，创造闪烁效果
                    if (random.nextDouble() < 0.05) {
                        charIndex = random.nextInt(chars.length());
                        c = chars.charAt(charIndex);
                    }

                    // 绘制字符
                    g2d.drawString(String.valueOf(c), i * FONT_SIZE, y);
                }
            }

            // 绘制字符流头部更亮的字符
            int headY = col.yPosition - FONT_SIZE;
            if (headY > 0 && headY < HEIGHT) {
                // 头部字符更亮
                g2d.setColor(new Color(180, 255, 180));
                int charIndex = random.nextInt(chars.length());
                char c = chars.charAt(charIndex);
                g2d.drawString(String.valueOf(c), i * FONT_SIZE, headY);
            }
        }
    }

    // 创建鼠标位置的扰动效果
    private void createMouseDisturbance() {
        int mouseColumn = mouseX / FONT_SIZE;
        if (mouseColumn >= 0 && mouseColumn < columns) {
            // 鼠标附近的列有概率被扰动
            for (int i = mouseColumn - 5; i <= mouseColumn + 5; i++) {
                if (i >= 0 && i < columns && random.nextDouble() < 0.1) {
                    columnsArray[i].reset();
                }
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 更新每列的位置
        for (Column col : columnsArray) {
            col.update();
        }
        // 重绘
        repaint();
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        mouseX = e.getX();
        mouseY = e.getY();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        mouseMoved(e);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Improved Matrix Rain");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(true);
            frame.add(new MatrixRain());
            frame.pack();
            frame.setLocationRelativeTo(null); // 居中显示
            frame.setVisible(true);
        });
    }
}
